package cn.edu.xjtu.android.emoji_warfare_android.engine.entity;

import android.graphics.Canvas;
import cn.edu.xjtu.android.emoji_warfare_android.engine.shape.Shape;

/**
 * 实体类<br>
 * 此类用于描述一个实体，包括：<br>
 * 1.玩家、敌人<br>
 * 2.子弹，激光<br>
 * 3.血条、技能槽等<br>
 * 一个实体由一个原点、轮廓(碰撞箱)组成<br>
 * 此类的正确用法：<br>
 * 1.传入一个形状，例如从Config中的公用形状。<br>
 * 2.通过get方法获取该Entity的原点坐标，并保留该引用。<br>
 * 3.覆写onDraw方法，使得该实体可以正常绘制。<br>
 * 4.如果需要移动该实体，直接设置原点坐标引用中的数据即可。 由于final特性，始终能够移动该实体。
 * 例如在Controller中保存原点引用，直接设置即可移动该实体<br>
 * 5.使用isOverlap判断两个实体之间是否碰撞，例如在物理引擎中进行判断<br>
 * 说明：<br>
 * 该类不允许传入一个原点引用，是为了防止造成原点位置不能一一对应，因此原点应由Entity本身创建。
 * 
 * @author bill
 *
 */
public class Entity {
    /**
     * 原点<br>
     * 该实体的原点在世界坐标系的位置<br>
     * 例如一个球体，这个球的中心在屏幕上的位置为(100,100)，则basePoint就是(100,100)
     */
    public final Point basePoint;
    /**
     * 碰撞箱<br>
     * 表示这个实体的碰撞箱<br>
     * 碰撞箱Shape中持有basePoint引用，根据这个来确定碰撞箱的世界坐标系位置<br>
     * Shape有isOverlap(Shape)方法来判断是否和另一个碰撞箱相碰撞，以此达到碰撞检测的目的<br>
     */
    public final Shape outline;

    /**
     * 根据给定形状构造一个实体。<br>
     * 传入参数仅有形状，原点不提供创建、传入的功能。<br>
     * 需要移动该实体，应该使用getBasePoint获取原点引用， 并直接修改该引用的x和y即可。
     * 
     * @param birthX
     *            出生点x坐标
     * @param birthY
     *            出生点y坐标
     * @param outline
     *            轮廓
     */
    public Entity(float birthX, float birthY, Shape outline) {
        if (outline == null) {
            throw new IllegalArgumentException("The outline of a shape can't be null");
        } else {
            this.basePoint = new Point();
            this.basePoint.x = birthX;
            this.basePoint.y = birthY;
            this.outline = outline;
        }
    }

    public Entity(Point basePoint, Shape outline) {
        if (outline == null) {
            throw new IllegalArgumentException("The outline of a shape can't be null");
        }
        if (basePoint == null) {
            throw new IllegalArgumentException("The basePoint of a shape can't be null");
        }
        this.basePoint = basePoint;
        this.outline = outline;
    }

    /**
     * 根据给定形状构造一个实体。<br>
     * 传入参数仅有形状，原点不提供创建、传入的功能。<br>
     * 需要移动该实体，应该使用getBasePoint获取原点引用， 并直接修改该引用的x和y即可。
     * 
     * @param outline
     *            轮廓
     */
    public Entity(Shape outline) {
        this(0, 0, outline);
    }

    /**
     * 判断该实体是否和目标实体碰撞
     * 
     * @param object
     *            客体对象
     * @return 是否碰撞，碰撞为真，未碰撞为假
     */
    public boolean isOverlap(Entity object) {
        return CollideCheck.isOverlap(this, object);
    }

    /**
     * draw方法<br>
     * 该实体的绘制方法<br>
     * 传入一个画布参数，可视对象需要在此画布上绘制该对象<br>
     * 画布的(0,0)点是可视对象的原点(basePoint)<br>
     * 向负坐标绘制图像是可行的(不用怕坐标小于0无法绘制图像)<br>
     * 如果留空则不进行绘制，如物理引擎和图像引擎的边界实体不需要绘制。<br>
     * 返回值标识这个实体是否还需要离开图像引擎，真为不再绘制这个实体，假为继续绘制。<br>
     * 注意！请不要移动画布，否则会造成渲染混乱！！<br>
     * 如果一定要移动画布，请移动完毕后移回原位
     * 
     * @param canvas
     *            画布
     * @return 是否删除该实体
     */
    public boolean onDraw(Canvas canvas) {
        return false;
    }
}
